defmodule SockWorkstation.CodecNifGen do
  use GenServer
  require Logger

  # @on_load :load_nif

  alias SockWorkstation.{CoopMgrGen,CodecNifGen}
  # alias SockWorkstation.FFmpegPlayer
  # @resource_type :codec_nif_resource

  @name __MODULE__
  def start_link(session_id) do
    GenServer.start_link(@name, session_id, name: via_tuple(session_id, "codec_nif"))
  end

  def get_state(session_id) do
    try do
      GenServer.call(via_tuple(session_id, "codec_nif"), :get_state)
    catch
      :exit, reason ->
        Logger.info("Failed to call GenServer: #{inspect(reason)}")
    end
  end

  @impl true
  def init(session_id) do
    self_pid = self()
    state = %{session_id: session_id}
    if Process.whereis(CoopMgrGen), do: CoopMgrGen.fetch_nif_pid(session_id, self_pid)
    IO.puts("CodecNifGen started: #{inspect(session_id)}")
    # load_nif(session_id)
    with :ok <- CodecNifGen.load_nif() do
      {:ok, state}
    else
      _ ->
        {:stop, :normal, state}
    end
  end

  defp priv_path(file) do
    Path.join(:code.priv_dir(:sock_workstation), file)
  end

  def load_nif() do
    lib_path = priv_path("codec_nif")

    case :erlang.load_nif(lib_path, 0) do
      :ok ->
        :ok

      {:error, {:reload, _}} ->
        :ok

      {:error, reason} ->
        raise "Failed to load NIF: #{reason}"
    end
  end

  # 初始化 NIF 资源
  # case :opus_nif.init() do
  #   {:ok, resource} ->
  #     {:ok, resource}

  #   {:error, reason} ->
  #     {:stop, reason}
  # end
  # end

  # 定义 NIF 函数的接口
  def encode_pcm(session_id, input) do
    GenServer.call(via_tuple(session_id, "codec_nif"), {:pcm_data, input})
  end

  def decode_opus(session_id, input) do
    GenServer.call(via_tuple(session_id, "codec_nif"), {:opus_data, input})
  end

  # not ok
  # @impl true
  def encode_pcm_data(pcm_data) do
    case encode_pcm_data(pcm_data) do
      {:ok, opus_data} ->
        {:ok, opus_data}

      {:error, reason} ->
        {:error, "Encoding failed: #{reason}"}
    end
  end

  # def encode_pcm_data(_input) do
  #   nif_not_loaded_error()
  # end

  # ok
  # @impl true
  def decode_opus_data(opus_data) do
    case decode_opus_data(opus_data) do
      {:ok, pcm_data} ->
        {:ok, pcm_data}

      {:error, reason} ->
        {:error, "Encoding failed: #{reason}"}
    end
  end

  # def decode_opus_data(_input) do
  #   nif_not_loaded_error()
  # end

  # defp nif_not_loaded_error do
  #   raise "NIF library not loaded. Ensure the NIF is properly loaded before calling this function."
  # end

  # 处理 NIF 函数调用
  @impl true
  def handle_call(:get_state, _from, state) do
    {:reply, state, state}
  end

  def handle_call({:pcm_data, input}, _from, state) do
    # if state.nif_loaded do
    # 调用 NIF 函数
    result = encode_pcm_data(input)
    {:reply, result, state}
    # else
    #   {:reply, {:error, :nif_not_loaded}, state}
    # end
  end

  def handle_call({:opus_data, input}, _from, state) do
    # if state.nif_loaded do
    # 调用 NIF 函数
    result = decode_opus_data(input)
    {:reply, result, state}
    # else
    #   {:reply, {:error, :nif_not_loaded}, state}
    # end
  end

  # @impl true
  # def terminate(_reason, state) do
  #   CoopMgrGen.rm_nif_pid(state.session_id)
  #   # :codec_nif.unload(state)
  #   # :erlang.nif_error(:nif_not_loaded)
  #   # :erlang.exit(:normal)
  #   # :ok
  #   # exit(:normal)

  #   {:stop, :normal, state}
  # end

  defp via_tuple(session_id, type) do
    {:via, Registry, {SockWorkstation.SessionRegistry, {session_id, type}}}
  end
end
